#pragma once

#include "export.h"
#include "node.h"
#include "vec.h"
#include "quat.h"
#include "defaultmanipulator.h"


class DENG_EXPORT CameraPose 
{
public:
  CameraPose() {cx=cy=cz=cd=ra=ry=rz=0; rx=1;};
  CameraPose( Vec c, double d, Quat q) {cx=c.x; cy=c.y; cz=c.z; cd=d; ra=q.a; rx=q.x; ry=q.y; rz=q.z;};
  CameraPose( double x, double y, double z, double d, double qa,  double qx, double qy, double qz ) 
            {cx=x; cy=y; cz=z; cd=d; ra=qa; rx=qx; ry=qy; rz=qz;};

  virtual ~CameraPose() {};

  double cx,cy,cz; //center
  double cd; //distance
  double ra,rx,ry,rz; //rotation

  CameraPose Mul(double m)      {return CameraPose(cx*m, cy*m, cz*m, cd*m, ra*m, rx*m, ry*m, rz*m);}; 
  CameraPose Sum(CameraPose c)  {return CameraPose(cx+c.cx, cy+c.cy, cz+c.cz, cd+c.cd, ra+c.ra, rx+c.rx, ry+c.ry, rz+c.rz);};

  std::string Repr() {std::ostringstream os; 
                      os << "(" << cx <<", " << cy <<", " << cz <<", " ; 
                      os <<  cd <<", ";
                      os <<  ra <<", " << rx <<", " << ry <<", " << rz <<")" ; 
                      return os.str();};

protected:
};


class DENG_EXPORT Manipulator 
{
  public:
    Manipulator();
    virtual ~Manipulator();

    CameraPose GetPose(  )        {return CameraPose( GetCenter(), GetDistance(), GetRotation() );};
    void  SetPose(CameraPose p)  {SetCenter(p.cx, p.cy, p.cz); SetDistance(p.cd); SetRotation(p.ra, p.rx, p.ry, p.rz);};

    void  SetCenter( double x, double y, double z )               {SetCenter( Vec(x,y,z) );};
    void  SetCenter( Vec center )                                 {_manip->setCenter( center.Get() );};
    Vec   GetCenter()                                             {return Vec( _manip->getCenter() );};

    void  SetDistance( float dist )                               {_manip->setDistance(dist);};
    float GetDistance()                                           {return _manip->getDistance(); };

    void  SetRotation( double a, double x, double y, double z )   {SetRotation( Quat(a,x,y,z) );};
    void  SetRotation( Quat rot )                                 {_manip->setRotation( rot.Get() );};
    Quat  GetRotation()                                           {return Quat(_manip->getRotation());};

    void  Fit(Node *n);

    void SetAllowThrow(bool b) {_manip->SetAllowThrow(b); };
    bool GetAllowThrow()       {return _manip->GetAllowThrow(); };

    DefaultManipulator* Get() {return _manip.get(); };
  protected:
    osg::ref_ptr<DefaultManipulator> _manip;
};


